/*
 * Copyright (c) 2011 Joe Kopena <tjkopena@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
*/

import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.geom.Rectangle;
import flash.ui.Keyboard;

import com.rocketshipgames.haxe.World;
import com.rocketshipgames.haxe.Engine;
import com.rocketshipgames.haxe.AssetCache;

import com.rocketshipgames.haxe.Entity;
import com.rocketshipgames.haxe.gfx.primitives.Spritesheet;
import com.rocketshipgames.haxe.physics.ShooterPhysicsPackage;

//----------------------------------------------------------------------
//----------------------------------------------------------------------
class PlayerPNG extends Bitmap
     { public function new() { super(); } }

class BulletPNG extends Bitmap
     { public function new() { super(); } }

//----------------------------------------------------------------------
//----------------------------------------------------------------------
class Bullet extends Entity {
  private static var _spritesheet:Spritesheet = null;
  private var _sprite:SpritesheetInstance;

  private static var XDRAG:Float = 2000;
  private static var ACCELERATION:Float = 8000;
  private static var MINIMUM_VELOCITY:Float = 20;
  private static var MAXIMUM_VELOCITY:Float = 1000;

  private var _physics:ShooterPhysicsPackage;

  public var dead:Bool;
  private var _deadpool:List<Bullet>;

  public function new(deadpool:List<Bullet>,
		      cache:AssetCache, x_:Float, y_:Float,
		      ?xvel:Float=0, ?yvel:Float=0):Void
  {
    // Configure the things that do not change across lives
    if (_spritesheet == null) {
      _spritesheet = new Spritesheet(cache, "assets/shooter/bullet.png", 7, 7,
				     false, false);
      _spritesheet.setAnimation(0, [0, 1], true);
    }
    super(_sprite = _spritesheet.newInstance(), x, y);
    _physics = new ShooterPhysicsPackage(this);

    _physics.offBoundsLeft = _physics.offBoundsRight =
      _physics.offBoundsTop = _physics.offBoundsBottom = offBounds;
    _physics.setBounds(BOUNDS_DETECT,
		       _spritesheet.width/2, _spritesheet.height/2,
		       World.rectangle.width-_spritesheet.width/2,
		       World.rectangle.height-_spritesheet.height/2);

    _physics.xacc = 0;
    _physics.xdrag = XDRAG;
    _physics.xvelMin = MINIMUM_VELOCITY;
    _physics.xvelMax = MAXIMUM_VELOCITY;
    _physics.yvelMin = MINIMUM_VELOCITY;
    _physics.yvelMax = MAXIMUM_VELOCITY;

    _deadpool = deadpool;

    trace("!");

    // Now set things that change per life
    init(x_, y_, xvel, yvel);

    // end function new
  }

  public function init(x_:Float, y_:Float,
		       ?xvel:Float=0, ?yvel:Float=0)
  {
    dead = false;
    _sprite.play(0);

    x = x_;
    y = y_;
    _physics.xvel = xvel;
    _physics.ydrag = yvel;
    // end public function init
  }

  public override function update():Void
  {
    if (dead)
      return;

    _physics.yacc = -ACCELERATION;
    _physics.update();
    super.update();
    // end function update
  }

  public override function render():Void
  {
    if (dead)
      return;
    super.render();
  }

  private function offBounds():Void
  {
    // _parent.remove(this);
    dead = true;
    _deadpool.push(this);
    // end function offBounds
  }

  // end class Bullet
}

//----------------------------------------------
class Player extends Entity {
  private static var _spritesheet:Spritesheet = null;
  private var _sprite:SpritesheetInstance;

  private static var IDLE_FRAME:Int = 0;
  private static var MOVE_FRAME:Int = 1;

  private static var ACCELERATION:Float = 2000;
  private static var MINIMUM_VELOCITY:Float = 2;
  private static var MAXIMUM_VELOCITY:Float = 500;

  private var _physics:ShooterPhysicsPackage;

  private var _cache:AssetCache;

  private static var SHOT_INTERVAL:Int = 100;
  private var _shotClock:Int;

  private var _shotpool:List<Bullet>;

  public function new(cache:AssetCache, x:Float, y:Float):Void
  {
    _cache = cache;

    if (_spritesheet == null) {
      _spritesheet = new Spritesheet(cache, "assets/shooter/player.png", 27, 26,
				    false, false);
    }
    super(_sprite = _spritesheet.newInstance(), x, y);
    _sprite.setFrame(IDLE_FRAME);

    _shotpool = new List();

    _physics = new ShooterPhysicsPackage(this);

    _physics.xdrag = ACCELERATION;
    _physics.xvelMin = MINIMUM_VELOCITY;
    _physics.xvelMax = MAXIMUM_VELOCITY;

    _physics.ydrag = ACCELERATION;
    _physics.yvelMin = MINIMUM_VELOCITY;
    _physics.yvelMax = MAXIMUM_VELOCITY;

    _physics.setBounds(BOUNDS_STOP,
		       _spritesheet.width/2, _spritesheet.height/2,
		       World.rectangle.width-_spritesheet.width/2,
		       World.rectangle.height-_spritesheet.height/2);

    _shotClock = 0;
      // end function new
  }

  public override function update():Void
  {

      // Detect inputs, set acceleration forces appropriately
    _physics.xacc = 0;
    _physics.yacc = 0;

      if (World.keyDown[Keyboard.LEFT]) {
	_physics.xacc -= ACCELERATION;
      }

      if (World.keyDown[Keyboard.RIGHT]) {
	_physics.xacc += ACCELERATION;
      }

      if (World.keyDown[Keyboard.UP]) {
	_physics.yacc -= ACCELERATION;
      }

      if (World.keyDown[Keyboard.DOWN]) {
	_physics.yacc += ACCELERATION;
      }

    _shotClock -= World.elapsed;
      if (World.keyDown[Keyboard.SPACE]) {
	if (_shotClock <= 0) {
	  if (_shotpool.isEmpty()) {
	    _parent.add(new Bullet(_shotpool, _cache,
				   x, y-_spritesheet.height/2,
				   _physics.xvel, _physics.yvel), 1);
	  } else {
	    _shotpool.pop().init(x, y-_spritesheet.height/2,
				 _physics.xvel, _physics.yvel);
	  }
	  _shotClock = SHOT_INTERVAL;
	}
      }

      // Run the shooter physics---movement, screen bounds, etc
      _physics.update();
      super.update();

      // Set the appropriate animation based on how the ship's moving
      if (_physics.xvel == 0 && _physics.yvel == 0) {
	_sprite.setFrame(IDLE_FRAME);
      } else {
	_sprite.setFrame(MOVE_FRAME);
      }

    // end function update
  }

  // end class Player
}

//----------------------------------------------------------------------
//----------------------------------------------------------------------
class Ex50Deadpool extends Engine
{

  public function new(cache:AssetCache):Void
  {
    trace("Starting");
    super(640, 480);
    add(new Player(cache, 320, 240));
    // end new
  }

  private override function render():Void
  {
    World.buffer.fillRect(World.rectangle,
			  0xff000000);
    super.render();
    // end function render
  }

   // Entry point for haXe
   static public function main()
   {
     com.rocketshipgames.haxe.Debug.enableConsoleTrace();

     var cache:AssetCache = null;
     cache = new AssetCache
       (function(){ if (!cache.error) new Ex50Deadpool(cache); });
     cache.addBitmapData("assets/shooter/player.png", false, new PlayerPNG());
     cache.addBitmapData("assets/shooter/bullet.png", false, new BulletPNG());
     cache.lock();

     // end main
   }

  // end Ex50Deadpool
}
